#include "ScriptPCH.h"
#include "lost_city_of_the_tolvir.h"
#include "Vehicle.h"

enum Spells
{
    // Pygmy Brute
    SPELL_IMPALE                = 83783,
    SPELL_SHOCKWAVE             = 83785,

    // Wind Tunnel
    SPELL_SLIPSTREAM            = 85016,
};


const Position RopeBeamPos[8]=
{
    { -11095.3f, -1357.22f, 11.5751f, 0.0f },
    { -11093.6f, -1356.25f, 17.2975f, 0.0f },
    { -11097.3f, -1347.20f, 17.1596f, 0.0f },
    { -11099.0f, -1347.01f, 11.4107f, 0.0f },
    { -11087.8f, -1379.89f, 11.4035f, 0.0f },
    { -11086.9f, -1378.05f, 17.2635f, 0.0f },
    { -11090.6f, -1369.01f, 17.2757f, 0.0f },
    { -11092.2f, -1367.89f, 11.1261f, 0.0f },
};

const uint32 SpellRopBeam[4] = { 84168, 84167, 84171, 84172 };

class npc_enslaved_bandit_tv : public CreatureScript
{
    public:
        npc_enslaved_bandit_tv() : CreatureScript("npc_enslaved_bandit_tv") { }

        struct npc_enslaved_bandit_tvAI : public ScriptedAI
        {
            npc_enslaved_bandit_tvAI(Creature* creature) : ScriptedAI(creature)
            {
                RopeBeam();
            }

            void Reset() override { }

            void RopeBeam()
            {
                if (me->GetDistance2d(RopeBeamPos[0].m_positionX, RopeBeamPos[0].m_positionY) < 10.0f)
                {
                    me->SetCanFly(true);
                    me->setActive(true);
                    me->SetReactState(REACT_PASSIVE);
                    me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);

                    for (int i = 0; i < 4; ++i)
                        if (Creature* beam = me->SummonCreature(37231, RopeBeamPos[i]))
                        {
                            beam->setActive(true);
                            beam->SetCanFly(true);
                            me->CastSpell(beam, SpellRopBeam[i], true);
                        }
                }
                else if (me->GetDistance2d(RopeBeamPos[4].m_positionX, RopeBeamPos[4].m_positionY) < 10.0f)
                {
                    me->SetCanFly(true);
                    me->setActive(true);
                    me->SetReactState(REACT_PASSIVE);
                    me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);

                    for (int i = 4; i < 8; ++i)
                        if (Creature* beam = me->SummonCreature(37231, RopeBeamPos[i]))
                        {
                            beam->setActive(true);
                            beam->SetCanFly(true);
                            me->CastSpell(beam, SpellRopBeam[i - 4], true);
                        }
                }

                ScriptedAI::EnterEvadeMode();
            }

            void UpdateAI(uint32 /*diff*/) override
            {
                if (!UpdateVictim())
                    return;

                DoMeleeAttackIfReady();
            }
        };

        CreatureAI* GetAI(Creature* creature) const override
        {
            return GetInstanceAI<npc_enslaved_bandit_tvAI>(creature);
        }
};

class npc_pygmy_brute_tv : public CreatureScript
{
    public:
        npc_pygmy_brute_tv() : CreatureScript("npc_pygmy_brute_tv") { }

        struct npc_pygmy_brute_tvAI : public ScriptedAI
        {
            npc_pygmy_brute_tvAI(Creature* creature) : ScriptedAI(creature) { }

            uint32 uiSummonTimer;
            uint32 uiImpaleTimer;
            uint32 uiShockwaveTimer;
            uint8 uiSummonMask;

            void Reset() override
            {
                uiSummonTimer = 500;
                uiImpaleTimer = urand(3000, 7000);
                uiShockwaveTimer = urand(7000, 15000);
                uiSummonMask = 1;
            }

            void UpdateAI(uint32 diff) override
            {
                if (uiSummonMask)
                {
                    if (uiSummonTimer <= diff)
                    {
                        if (Vehicle* vehicle = me->GetVehicleKit())
                        {
                            float x, y, z;
                            me->GetPosition(x, y, z);
                            uiSummonTimer = 500;

                            switch (uiSummonMask)
                            {
                                case 1:
                                    {
                                        ++uiSummonMask;

                                        if (!vehicle->GetPassenger(0))
                                            if (TempSummon* pygmy = me->SummonCreature(44897, x, y, z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 30000))
                                                pygmy->EnterVehicle(me);
                                    }
                                    break;
                                case 2:
                                    {
                                        uiSummonMask = 0;

                                        if (Unit* passenger = vehicle->GetPassenger(0))
                                            if (Vehicle* veh_pygmy = passenger->GetVehicleKit())
                                                if (!veh_pygmy->GetPassenger(0))
                                                    if (Creature* pygmy = me->SummonCreature(44898, x, y, z, 0.0f, TEMPSUMMON_CORPSE_DESPAWN, 30000))
                                                        pygmy->EnterVehicle(passenger);
                                    }
                                    break;
                            }
                        }
                    }
                    else
                        uiSummonTimer -= diff;
                }

                if (!UpdateVictim())
                    return;

                if (uiImpaleTimer <= diff)
                {
                    uiImpaleTimer = urand(10000, 25000);
                    me->CastSpell(me->GetVictim(), 83783, false);
                }
                else
                    uiImpaleTimer -= diff;

                if (uiShockwaveTimer <= diff)
                {
                    uiShockwaveTimer = urand(10000, 25000);
                    me->CastSpell(me, 83785, false);
                }
                else
                    uiShockwaveTimer -= diff;

                DoMeleeAttackIfReady();
            }
        };

        CreatureAI* GetAI(Creature* creature) const override
        {
            return GetInstanceAI<npc_pygmy_brute_tvAI>(creature);
        }
};

struct SlipstreamPlayer
{
    uint64 uiPlayerGUID;
    uint32 uiPersonalTimer;
};

class npc_wind_tunnel : public CreatureScript
{
    public:
        npc_wind_tunnel() : CreatureScript("npc_wind_tunnel") { }

        struct npc_wind_tunnelAI : public ScriptedAI
        {
            npc_wind_tunnelAI(Creature* creature) : ScriptedAI(creature)
            {
                instance = creature->GetInstanceScript();
                me->setActive(true);
            }

            InstanceScript* instance;
            std::list<SlipstreamPlayer> lPlayers;
            uint8 uiIdentifier;

            void Reset() override
            {
                me->SetFlag(UNIT_FIELD_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
                if (instance->GetData(DATA_HIGH_PROPHET_BARIM) != DONE)
                    me->SetVisible(false);
                else
                    me->SetVisible(true);
            }

            void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
            {
                if (apply && who->GetTypeId() == TYPEID_PLAYER)
                {
                    SlipstreamPlayer new_player;
                    new_player.uiPlayerGUID = who->GetGUID();
                    new_player.uiPersonalTimer = 2000;
                    lPlayers.push_back(new_player);
                }
            }

            void UpdateAI(uint32 diff) override
            {
                if (lPlayers.empty())
                    return;

                for (std::list<SlipstreamPlayer>::iterator itr = lPlayers.begin(); itr != lPlayers.end();)
                {
                    if ((*itr).uiPersonalTimer <= diff)
                    {
                        if (Player* player = Unit::GetPlayer(*me, (*itr).uiPlayerGUID))
                            if (Creature* Landing = me->FindNearestCreature(48097, 100.0f))
                            {
                                player->ExitVehicle();
                                player->CastSpell(player, SPELL_SLIPSTREAM, true);
                                player->CastSpell(Landing, 46598, true);

                                if (Aura* aura = Landing->GetAura(46598, (*itr).uiPlayerGUID))
                                    aura->SetDuration(1000);
                            }

                        itr = lPlayers.erase(itr);
                    }
                    else
                    {
                        (*itr).uiPersonalTimer -= diff;
                        ++itr;
                    }
                }
            }
        };

        CreatureAI* GetAI(Creature* creature) const override
        {
            return GetInstanceAI<npc_wind_tunnelAI>(creature);
        }
};

void AddSC_lost_city_of_the_tolvir()
{
    new npc_enslaved_bandit_tv();
    new npc_pygmy_brute_tv();
    new npc_wind_tunnel();
}